//-----------------------------------------------------------------------------------
#include "AIStar.h"
//-----------------------------------------------------------------------------------
AIStar::AIStar()
:
m_iMapaWidth(0),
m_iMapaHeight(0)
{

}
//-----------------------------------------------------------------------------------
AIStar::AIStar( int iMapa[][MAX_COL], int iMapaWidth, int iMapaHeight )
:
m_iMapaWidth(iMapaWidth),
m_iMapaHeight(iMapaHeight)
{
	int iCost = 0;

	m_vAllStarNodes.resize(m_iMapaWidth + 1);

	for( int i = 0; i < m_iMapaWidth + 1; i++ )
	{
		m_vAllStarNodes[i].resize(m_iMapaHeight + 1);

		for( int j = 0; j < m_iMapaHeight + 1; j++ )
		{
			if( iMapa[i][j] > -1 )
			{
				iCost = iMapa[i][j];
			}
			else
			{
				iCost = 0;
			}

			m_vAllStarNodes[i][j] = new StarNode( i, j, iMapa[i][j], iCost );
		}
	}
}
//-----------------------------------------------------------------------------------
AIStar::~AIStar()
{
	
}
//-----------------------------------------------------------------------------------
void AIStar::InitializeASTar(int iMapa[][MAX_COL], int iMapaWidth, int iMapaHeight )
{
	m_iMapaWidth = iMapaWidth;
	m_iMapaHeight = iMapaHeight;
	m_iStartCol = 0;
	m_iStartRow = 0;
	m_iExitCol = 0;
	m_iExitRow = 0;
	m_pkStarNode = NULL;

	int iCost = 0;

	m_vAllStarNodes.resize(m_iMapaWidth + 1);

	for( int i = 0; i < m_iMapaWidth + 1; i++ )
	{
		m_vAllStarNodes[i].resize(m_iMapaHeight + 1);

		for( int j = 0; j < m_iMapaHeight + 1; j++ )
		{
			if( iMapa[i][j] > -1 )
			{
				iCost = iMapa[i][j];
			}
			else
			{
				iCost = 0;
			}

			m_vAllStarNodes[i][j] = new StarNode( i, j, iMapa[i][j], iCost );
		}
	}
}
//-----------------------------------------------------------------------------------
sPosition ** AIStar::FindPath( int iColStart,
							   int iRowStart,
							   int iColExit,
							   int iRowExit )
{
	int iIndex = 0;

	m_iExitCol = iColExit;
	m_iExitRow = iRowExit;
	m_iStartCol = iColStart;
	m_iStartRow = iRowStart;

	if( ( ( m_iStartCol < 0 ) || ( m_iStartRow < 0 ) 
		|| ( m_iStartCol < 0 ) || ( m_iStartRow < 0 ) ) 
		|| ( ( m_iStartCol > m_iMapaHeight ) 
		|| ( m_iStartRow > m_iMapaWidth ) 
		|| ( m_iStartCol > m_iMapaHeight ) 
		|| ( m_iStartRow > m_iMapaWidth ) ) )
	{
		return NULL;
	}

	m_vOpenStarNodes.push_back( m_vAllStarNodes[m_iStartRow][m_iStartCol] );
	
	m_pkStarNode = m_vOpenStarNodes[iIndex];

	while( !m_vOpenStarNodes.empty() )
	{		
		m_pkStarNode = GetLowerStarNode();

		if( m_pkStarNode == m_vAllStarNodes[m_iExitRow][m_iExitCol] )
		{
			m_vClosedStarNodes.push_back(m_pkStarNode);

			return m_pkStarNode->NormalizePath();
		}

		m_vClosedStarNodes.push_back( m_pkStarNode );

		RemoveStarNode( m_pkStarNode );

		OpenAdyacents( m_pkStarNode );
	}

	if( m_pkStarNode == m_vAllStarNodes[m_iExitRow][m_iExitCol] )
	{
		return m_pkStarNode->NormalizePath();
	}

	return NULL;
}
//-----------------------------------------------------------------------------------
void AIStar::OpenAdyacents( StarNode * pStarNode )
{
	if( (pStarNode->m_sPosition.m_isRow > 0) &&
		(pStarNode->m_sPosition.m_isRow <= m_iMapaWidth)&&
		(pStarNode->m_iType != TYPE_WALL))
	{
		TryToOpen(pStarNode, m_vAllStarNodes[pStarNode->m_sPosition.m_isRow - 1][pStarNode->m_sPosition.m_isCol]);
	}

	if( (pStarNode->m_sPosition.m_isRow >= 0) &&
		(pStarNode->m_sPosition.m_isRow <= m_iMapaWidth - 1)&&
		(pStarNode->m_iType != TYPE_WALL))
	{
		TryToOpen(pStarNode, m_vAllStarNodes[pStarNode->m_sPosition.m_isRow + 1][pStarNode->m_sPosition.m_isCol]);
	}

	if( (pStarNode->m_sPosition.m_isCol <= m_iMapaHeight - 1) &&
		(pStarNode->m_sPosition.m_isCol >= 0) &&
		(pStarNode->m_iType != TYPE_WALL))
	{
		TryToOpen(pStarNode, m_vAllStarNodes[pStarNode->m_sPosition.m_isRow][pStarNode->m_sPosition.m_isCol + 1]); 
	}

	if( (pStarNode->m_sPosition.m_isCol > 0) && 
		(pStarNode->m_sPosition.m_isCol <= m_iMapaHeight) &&
		(pStarNode->m_iType != TYPE_WALL))
	{
		TryToOpen(pStarNode, m_vAllStarNodes[pStarNode->m_sPosition.m_isRow][pStarNode->m_sPosition.m_isCol - 1]); 
	}
}
//-----------------------------------------------------------------------------------
int AIStar::GetManhattan( StarNode * pStarNodeStart, StarNode * pStarNodeExit )
{
	return ( abs( pStarNodeStart->m_sPosition.m_isCol - pStarNodeExit->m_sPosition.m_isCol ) 
		   + abs( pStarNodeStart->m_sPosition.m_isRow - pStarNodeExit->m_sPosition.m_isRow ) );
}
//-----------------------------------------------------------------------------------
StarNode * AIStar::GetLowerStarNode()
{
	StarNode * pkRetStarNode = m_vOpenStarNodes[0];

	int iCostAux = 0;

	int iMinCost = m_vOpenStarNodes[0]->m_iCost + GetManhattan( m_vOpenStarNodes[0], 
			m_vAllStarNodes[m_iExitRow][m_iExitCol] );

	int iSize = (int)m_vOpenStarNodes.size();
	
	for( int i = 1; i < iSize; i++ )
	{
		iCostAux = m_vOpenStarNodes[i]->m_iCost + GetManhattan( m_vOpenStarNodes[i], 
			m_vAllStarNodes[m_iExitRow][m_iExitCol] );

		if( iCostAux <= iMinCost )
		{
			iMinCost = iCostAux;
			pkRetStarNode = m_vOpenStarNodes[i];
		}
	}

	return pkRetStarNode;
}
//-----------------------------------------------------------------------------------
void AIStar::RemoveStarNode(StarNode * pkStarNode)
{
	std::vector<StarNode *>::iterator it;

	for( it = m_vOpenStarNodes.begin(); it < m_vOpenStarNodes.end(); it++ )
	{
		if( *it == pkStarNode )
		{
			m_vOpenStarNodes.erase(it);

			break;
		}
	}
}
//-----------------------------------------------------------------------------------
bool AIStar::IsOpen(StarNode * pkStarNode)
{
	int iSize = (int)m_vOpenStarNodes.size();

	for(int i = 0; i < iSize; i++)
	{	
		if( pkStarNode == m_vOpenStarNodes[i] )
		{
			return true;
		}
	}

	return false;
}
//-----------------------------------------------------------------------------------
bool AIStar::IsClosed(StarNode * pkStarNode)
{
	int iSize = (int)m_vClosedStarNodes.size();

	for(int i = 0; i < iSize; i++)
	{	
		if( pkStarNode == m_vClosedStarNodes[i] )
		{
			return true;
		}
	}

	return false;
}
//-----------------------------------------------------------------------------------
void AIStar::TryToOpen(StarNode * pkParentStarNode, StarNode * pkStarNode)
{
	if( !IsOpen(pkStarNode) && !IsClosed(pkStarNode) && pkStarNode->m_iType != TYPE_WALL )
	{
		m_vOpenStarNodes.push_back(pkStarNode);
		pkStarNode->m_npParent = pkParentStarNode;
		pkStarNode->m_iCost += pkParentStarNode->m_iCost + 1;
	}
}
//-----------------------------------------------------------------------------------
void AIStar::ClearAStar()
{
	m_vOpenStarNodes.clear();
	m_vClosedStarNodes.clear();

	m_pkStarNode = NULL;

	m_iMapaWidth = 0;
	m_iMapaHeight = 0;
	m_iStartCol = 0;
	m_iStartRow = 0;
	m_iExitCol = 0;
	m_iExitRow = 0;
}
//-----------------------------------------------------------------------------------